2023-11-22
قراره مدل های مختلف سری زمانی رو به داده های دوج کوین برازش کنیم!
Ritvik Kharkar
این داداشمون اسمش ریتویک خارکار هست که ویدیو های سری زمانی ایشون رو می تونید تو یوتیوب رایگان ببینید! یکی دوره های پولسازی آشغالشو میلیونی میفروشه از اون طرف یکی دیگه به رایگان بهترین مطالب رو به اشتراک میزاره!
دستور زیر رو در لینوکس اجرا کنید تا داده ها از نوبیتکس دانلود بشه
با تغییر resolution و symbol می تونید دادههای متفاوت بگیرید ، مثلاً symbol=BTCIRT داده بیتکوین میده
import json
import pandas as pd
file = 'DOGEIRT-D'
with open(file+'.json') as train_file:
dict1 = json.load(train_file)
# converting json dataset from dictionary to dataframe
df = pd.DataFrame(data=dict1)
df = df.drop('s', axis=1)
df['t'] = pd.to_datetime(df['t'],unit='s')
df = df.set_index('t')
df.index = pd.DatetimeIndex(df.index).to_period('D')
df.to_csv(file+'.csv')اینا کد پایتونه، از اسلاید بعد همه کد ها تو R هست
ارزیابی بلند مدت
ارزیابی کوتاه مدت
\(P_i\) مقدار پیش بینی شده و \(A_i\) مقدار واقعی هست.
\[MSE = \frac{1}{n}\sum_{i=1}^{n}(A_i-P_i)^2\] \[RMSE = \sqrt{MSE}\] \[MAD = \frac{1}{n}\sum_{i=1}^{n}|A_i-P_i|\]
فعلا آخرین قیمت closed price را به عنوان متغییر پاسخ در نظر میگیریم.
library(zeallot)
res_prep = function(pred,lpred,lfun){
res = matrix(nrow = length(lfun),ncol = length(lpred))
rownames(res) = names(lfun)
colnames(res) = names(lpred)
colnames(pred) = names(lpred)
for (i in 1:length(lfun)) {
res[i,] = apply(pred,2,FUN = lfun[[i]])
}
return(list(pred = pred, res = res))
}
LTE = function(lpred,data,xname="t",yname="c",percent=0.8) {
tr = head(data,round(nrow(data)*percent))
ts = tail(data,nrow(data)-nrow(tr))
extra.info = list()
pred = matrix(nrow = nrow(ts))
yind = which(colnames(ts)==yname)
for (n in names(lpred)){
lpred.out = lpred[[n]](tr,ts[,-yind,drop=FALSE])
pred = cbind(pred,lpred.out[["pred"]])
extra.info[[n]] = lpred.out[["extra.info"]]
}
pred = pred[,-1,drop=FALSE]
lfun = list(RMSE=function(x) sqrt(mean((x-ts[,yname])^2)),MAD=function(x) mean(abs(x-ts[,yname])))
c(pred,res) %<-% res_prep(pred,lpred,lfun)
# Plot
fx = as.formula(paste("~",xname))
fy = as.formula(paste("~",yname))
fig = plot_ly(mode="lines", type = "scatter")%>%
add_trace( data=tr, x = fx, y = fy,name = "train")%>%
add_trace(data=ts, x = fx, y = fy,name = "test")
for (n in colnames(pred))
fig = fig %>% add_trace(x=ts[,xname],y=pred[,n],name = n)
return (list(results = res, fig=fig, extra.info = extra.info))
}در اینجا از K-fold Cross Validation نمیتوان استفاده کرد.
باید از Rolling Cross Validation استفاده کنید که به دو روش sliding و expanding می تونه انجام بشه!
اما ممکنه بپرسید که اصلا Cross Validation چی هست؟!
STE = function(lpred,data,xname="t",yname="c",startp=0.97,sliding.time=30,is.plot=TRUE) {
tr = head(data,round(nrow(data)*startp))
ts = tail(data,nrow(data)-nrow(tr))
fx = as.formula(paste("~",xname))
fy = as.formula(paste("~",yname))
fig.base = plot_ly(mode="lines", type = "scatter")%>%
add_trace( data=tr, x = fx, y = fy,name = "train")%>%
add_trace(data=ts, x = fx, y = fy,name = "test")
pred.expand = matrix(nrow = nrow(ts),ncol = length(lpred))
pred.slide = matrix(nrow = nrow(ts), ncol = length(lpred))
yind = which(colnames(ts)==yname)
for (i in 1:nrow(ts)){
for (j in 1:length(lpred)){
pred.slide[i,j] = lpred[[j]](tail(tr,sliding.time),ts[i,-yind,drop=FALSE])[["pred"]]
pred.expand[i,j] = lpred[[j]](tr,ts[i,-yind,drop=FALSE])[["pred"]]
}
tr = rbind(tr,ts[i,])
}
lfun = list(RMSE=function(x) sqrt(mean((x-ts[,yname])^2)),MAD=function(x) mean(abs(x-ts[,yname])))
c(pred.expand,res.expand) %<-% res_prep(pred.expand,lpred,lfun)
c(pred.slide,res.slide) %<-% res_prep(pred.slide,lpred,lfun)
# Plot expanding
fig.ex = fig.base
fig.sl = fig.base
if(is.plot){
for (n in colnames(pred.expand))
fig.ex = fig.ex %>% add_trace(x=ts[,xname],y=pred.expand[,n],name = n)
# Plot sliding
for (n in colnames(pred.slide))
fig.sl = fig.sl %>% add_trace(x=ts[,xname],y=pred.slide[,n],name = n)
}
return(list(expanding=list(res=res.expand,fig=fig.ex), sliding = list(res=res.slide,fig=fig.sl)))
}این تابع یکسری پارامتر ها رو می تونه فیکس کنه.
f.fix <- function(fname,fixed) {
variable = c("tr","ts")
f.new <- function() {}
formals(f.new) <- setNames(rep(list(bquote()), length(variable)), variable)
for(i in variable) assign(i, as.symbol(i))
body(f.new) <- do.call("call", unlist(list(fname, fixed, mget(variable)),recursive = FALSE))
return(f.new)
}تشکر از GKI
m.lm_poly = function(tr,ts,n=2,x=NULL){
# Note that poly() returns Orthogonal Polynomials
if (!is.null(x)){
tr = tr[,c("t","c",x),drop=FALSE]
ts = ts[,c("t",x),drop=FALSE]
}
if (n==0)
m = lm(c~.,tr)
else
m = lm(c~poly(t,n)+.,tr)
return(list(pred = predict(m,ts), extra.info = m))
}
poly.list = list(Linear.Reg=f.fix("m.lm_poly",c(n=1)),
Quad.Reg=f.fix("m.lm_poly",c(n=2)),
Cubic.Reg=f.fix("m.lm_poly",c(n=3)),
Quartic.Reg=f.fix("m.lm_poly",c(n=4)) )
LTE.poly = LTE(poly.list,df,percent = 0.8)
LTE.poly$results Linear.Reg Quad.Reg Cubic.Reg Quartic.Reg
RMSE 13660.588 11013.619 8496.516 10426.42
MAD 9939.983 7489.811 7276.125 7721.51
Linear.Reg Quad.Reg Cubic.Reg Quartic.Reg
RMSE 12565.93 6430.872 5150.044 5581.286
MAD 11839.20 5114.542 4590.599 5009.681
Linear.Reg Quad.Reg Cubic.Reg Quartic.Reg
RMSE 2565.268 2274.630 1847.082 1905.489
MAD 2195.257 1914.668 1541.158 1653.001
توی این مدل همه داده ها تاثیر یکسانی روی مدل دارند. هرچقدر که این مدل سعی میکنه داده های جدید رو خوب فیت کنه ، همونقدر برای برازش مناسب داده های قدیمی تلاش میکنه! برای همین توی ارزشیابی بلند مدت خیلی خوب عمل نمیکنه!
فراموشی یک نعمت است!
همانطور که می دانید بازار همیشه پستی و بلندی داره! دوره ای نزول میکنه و دوره ای صعود! پس انتظار داریم منحنی پیش بینی شده هم بدون محدودیت ، صعود و نزول کنه و قله هایی رو بسازه. اما یک چند جمله ای درجه n نهایت n-1 قله داره.
به اختصار به این مدل ها میگیم SP!
Seasonal Polynomial = SP
قبل از انتخاب تعداد فصل ، بد نیست نگاهی به نمودار ACF بندازیم
[1] 0 38 2 13 27 5 25 22 7 10
بیایید L=38 را تست کنیم!
Linear.Reg Quad.Reg Cubic.Reg Quartic.Reg
RMSE 12743.58 6532.323 5206.721 5641.568
MAD 12007.34 5173.409 4646.200 5070.518
Linear.Reg Quad.Reg Cubic.Reg Quartic.Reg
RMSE 5064.047 4634.889 3286.310 3509.706
MAD 4540.562 3897.462 2744.228 2857.289
همونطور که دیدید اضافه کردن روند فصلی به مدل برای این داده ها تاثیری نداشت!
اول از همه، مدل سری فوریه به صورت زیر هست:
\[ Z_t = \alpha_0 + \sum_{i=1}^q(\alpha_iC_i(t)+\beta_iS_i(t)) + e_t \]
به طوری که
\[ S_i(t) = Sin(2\pi f_i t),\space C_i(t) = Cos(2\pi f_i t),\space f_i=i/L \]
حالا به این چند جمله ای اضافه کنید میشه PF.
fsr.x = c()
for (i in 1:4){
Sname = paste("S",i,"L38",sep = "")
Cname = paste("C",i,"L38",sep = "")
fsr.x = c(fsr.x,Sname,Cname)
df[,Sname] = sin(2*pi*(i/38)*df$t)
df[,Cname] = cos(2*pi*(i/38)*df$t)
}
head(df) t c L38 S1L38 C1L38 S2L38 C2L38 S3L38 C3L38
1 1 105.2 1 0.1645946 0.9863613 0.3246995 0.94581724 0.4759474 0.87947375
2 2 121.5 2 0.3246995 0.9458172 0.6142127 0.78914051 0.8371665 0.54694816
3 3 123.1 3 0.4759474 0.8794738 0.8371665 0.54694816 0.9965845 0.08257935
4 4 122.0 4 0.6142127 0.7891405 0.9694003 0.24548549 0.9157733 -0.40169542
5 5 122.0 5 0.7357239 0.6772816 0.9965845 -0.08257935 0.6142127 -0.78914051
6 6 118.9 6 0.8371665 0.5469482 0.9157733 -0.40169542 0.1645946 -0.98636130
S4L38 C4L38
1 0.6142127 0.7891405
2 0.9694003 0.2454855
3 0.9157733 -0.4016954
4 0.4759474 -0.8794738
5 -0.1645946 -0.9863613
6 -0.7357239 -0.6772816
pf.list = list(Cubic.H1=f.fix("m.lm_poly",list(n=3,x=fsr.x[1:2])),
Cubic.H2=f.fix("m.lm_poly",list(n=3,x=fsr.x[1:4])),
Cubic.H3=f.fix("m.lm_poly",list(n=3,x=fsr.x[1:6])),
Cubic.H4=f.fix("m.lm_poly",list(n=3,x=fsr.x[1:8]))
)
LTE.pf = LTE(pf.list,df)
LTE.pf$results Cubic.H1 Cubic.H2 Cubic.H3 Cubic.H4
RMSE 8499.544 8500.338 8500.275 8500.616
MAD 7281.397 7282.616 7283.577 7283.477
مدل های بهتری میخوای؟